// JavaScript是单线程的语言，由于JavaScript就是为了满足用户在前端页面的交互以及实现页面内容的动态，如果是多线程的，资源问题
// 解决成本大。

// 同步和异步
// 同步：同步是指JS引擎按照代码顺序来执行，遇到耗时的代码，就会影响交互，这也会导致阻塞
// 异步：JS引擎遇到相关的异步API时，将交给其他线程（浏览器就是浏览器提供的线程，例如：网络线程、定时器线程等；Node就是Libuv提供的线程，例如IO）
// 继续往下解析代码，直到解析完成之后；当其他线程处理完，再讲回调函数交由JS线程做处理。
// JavaScript线程会维护一个调用栈(call stack)和事件队列(Event Queue)，线程会优先处理栈里面的任务，当栈里面的任务清空时，开始事件循环，
// 去循环事件队列里面的任务，循环出来的任务，又会再推入当调用栈，如此循环下去。
// Promise
// Promise是ES6提供的一个语言层面的对象，目的就是去解决异步编程带来的回调嵌套，带来更加直观的异步编程体验

// Promise对象有三种状态，分别是pending、fullfilled、rejected。也分别提供了两个回调函数onFullfilled、onRejected去处理fullfilled、rejected
// 状态

// ----------基本用法
const promise = new Promise((resolve, reject) => {
  resolve(100);
});

promise.then(
  res => {
    console.log(`resolve: ${res}`);
  },
  e => {
    console.error(e);
  }
);

console.log('end');

// ----------基本应用
function ajax(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.responseType = 'json';
    xhr.onload = function () {
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(this.statusText);
      }
    };
    xhr.send();
  });
}

ajax('/api/info1.json').then(
  res => {
    console.log(res);
  },
  e => {
    console.error(e);
  }
);

ajax('/api/info.json')
  .then(
    function onFullfilled(person) {
      let name = '';
      for (const p of person) {
        if (p.name === 'cuvee') {
          name = p.name;
          break;
        }
      }
      return ajax(`/api/${name}.json`);
    },
    function onRejected(e) {}
  )
  .then(
    detail => {
      console.log(detail);
    },
    e => {
      console.error(e);
    }
  );

// catch方法也是调用了一个then方法，只是第一个参数传递的是undefined
// promise链条上，任何异常都能被catch捕捉到
const p1 = new Promise((resolve, reject) => {
  resolve(123);
});
p1.then(res => {
  console.log(res);
  return 456;
})
  .catch(e => {
    console.log(e);
  })
  .then(res => {
    console.log(res);
  });
// 浏览器和Node.js都提供了全局捕捉错误的回调函数。但是不推荐
window.addEventListener('unhandledrejection', err => {
  console.log(err);
});

// ----------静态方法
Promise.resolve('foo').then(res => {
  console.log(res);
});
// 等价于下面这个promise
// new Promise((resolve, reject) => {
//   resolve('foo');
// });

const p2 = ajax('/api/cuvee.json');
const p3 = Promise.resolve(p2);
console.log(p2 === p3);

Promise.resolve({
  then: (onFullfilled, onRejected) => {
    onFullfilled('foo');
  },
}).then(res => console.log(res));
// Promise.reject传入的参数只会被onRejected所接收，不论是什么类型的
// Promise.reject('error').catch(e => console.error(e));

// 并行
Promise.all([ajax('/api/cuvee.json'), ajax('/api/info.json')]).then(res => {
  console.log(res);
});
Promise.race([ajax('/api/cuvee.json'), ajax('/api/info.json')]).then(res => {
  console.log(res);
});
